#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_VAR 10
#define MAX_VALORES 100
#define MAX_TAM_NOME 100
#define REMOVIDO -1

typedef struct _Valores {
  int qtdadeValores;
  float valores[MAX_VALORES];
} Valores;



typedef struct _Variavel {
  int qtdadeVariaveis;
  char nome[MAX_VAR][MAX_TAM_NOME];
  Valores valores[MAX_VALORES];
} Variavel;





/**
 * @brief Função que inicializa uma Variável
 *
 * @return Retorna uma Variável
 */
Variavel inicializaVariavel (void) {
  Variavel outVar;
  /* inicializa com -1 para saber que está sem conteúdo */
  outVar.qtdadeVariaveis = -1;
  return outVar;
}




/**
 * @brief Função que imprime o Menu de opções
 */
void imprimeMenu (void) {
  puts ("- - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
  puts ("                        MENU                             ");
  puts ("- - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
  puts ("1 - Inserir variável aleatória");
  puts ("2 - Gravar variáveis aleatórias num arquivo");
  puts ("3 - Ler variáveis aleatórias de arquivo");
  puts ("4 - Comparar duas variáveis aleatórias");
  puts ("5 - Fazer regressão linear com duas variáveis aleatórias ");
  puts ("6 - Plotar");
  puts ("7 - Sair\n");
}




/**
 * @brief Função que insere uma Variavel
 *
 * @param var Variavel em que será inserida a nova variavel
 *
 * @return Retorna a mesma variavel de entrada com a nova variavel inserida
 */
Variavel inserir (Variavel var) {
  char nome[MAX_TAM_NOME];
  int qtdadeValores = 1;
  float valores[MAX_VALORES];
  int i;
  puts ("\n>>> Inserindo variável\n");
  /* incrementa o a quantidade de variaveis */
  var.qtdadeVariaveis++;
  /* recebe o nome da variavel */
  printf ("Nome: ");
  scanf (" %s", nome);
  do {
    /* recebe a quantidade de valores observados */
    printf ("Quantidade de valores observados: ");
    scanf (" %d", &qtdadeValores);
    /* verifica se a quantidade é maior do que 0 */
    if (qtdadeValores < 1) {
      puts ("\n>>> ERROR: A quantidade de valores deve ser no mínimo 1");
      puts (">>> Favor digite um valor acima de 0\n");
    }
  }while (qtdadeValores < 1);
  /* recebe os valores observados */
  for (i=0; i<qtdadeValores; i++) {
    printf ("Valor: ");
    scanf (" %f", &valores[i]);
  }
  /* insere o nome na variavel */
  strcpy (var.nome[var.qtdadeVariaveis] , nome);
  /* insere a quantidade de valores na variavel */
  var.valores[var.qtdadeVariaveis].qtdadeValores = qtdadeValores;
  /* insere os valores na variavel */
  for (i=0; i<qtdadeValores; i++) 
    var.valores[var.qtdadeVariaveis].valores[i] = valores[i];
  puts ("\n>>> Variável inserida com sucesso");
  /* retorna a variavel */
  return var;
}




/**
 * @brief Função que grava o conteúdo da Variável em um arquivo
 *
 * @param var Variavel que contém o que será gravado
 */
void gravar (Variavel var) {
  FILE *outFile;
  char endArquivo[MAX_TAM_NOME];
  int i, j;
  /* recebe o endereço do arquivo de saída */
  printf ("Digite o endereço do arquivo de saída: ");
  scanf (" %s", endArquivo);
  /* abre o arquivo para escrita */
  outFile = fopen (endArquivo, "w+");
  /* passeia pelas variaveis */
  for (i=0; i<=var.qtdadeVariaveis; i++) {
    /* verifica se a variavel não foi removida */
    if (var.valores[i].qtdadeValores != REMOVIDO) {
      /* imprime o nome no arquivo */
      fprintf (outFile, "%s ", var.nome[i]);
      /* imprime a quantidade de valores no arquivo */
      fprintf (outFile, "%d ", var.valores[i].qtdadeValores);
      /* passeia pelos valores da variavel */
      for (j=0; j<var.valores[i].qtdadeValores; j++) {
	/* imprime o valor observado no arquivo */
	fprintf (outFile, "%.2f ", var.valores[i].valores[j]);
      }
      /* imprime final de linha no arquivo */
      fprintf (outFile, "\n");
    }
  }
  /* fecha o arquivo */
  fclose(outFile);
  puts ("\n>>> Gravação realizada com sucesso");
  printf (">>> Arquivo gravado em %s\n", endArquivo);
}




/**
 * @brief Função que lê um arquivo de entrada e insere suas informações nas variáveis
 *
 * @param var Variavel que receberá as informações do arquivo de entrada
 *
 * @return Retorna a variavel de entrada com as informações inseridas
 */
Variavel ler (Variavel var) {
  FILE *inFile;
  char endArquivo[MAX_TAM_NOME];
  char nome[MAX_TAM_NOME];
  int qtdadeValores;
  float valores[MAX_VALORES];
  int i;
  int op;
  /* recebe o endereço do arquivo de entrada */
  printf ("Digite o endereço do arquivo de entrada: ");
  scanf (" %s", endArquivo);
  /* abre o arquivo para leitura */
  inFile = fopen (endArquivo, "r+");
  /* percorre o arquivo */
  while (!feof(inFile)) {
    /* incrementa a quantidade de variaveis */
    var.qtdadeVariaveis++;
    /* copia o nome */
    fscanf (inFile, " %s", nome);
    strcpy (var.nome[var.qtdadeVariaveis], nome);
    /* percorre as variaveis em busca de nomes repetidos */
    for (i=0; i<var.qtdadeVariaveis; i++) {
      /* caso encontre nome repetidos */
      if (strcmp (var.nome[i], nome) == 0   &&   var.valores[i].qtdadeValores != REMOVIDO) {
	/* mensagem de conflito */
	puts ("\n>>> ERROR: Conflito de variáveis");
	printf (">>> Conflito na variavel %s\n", nome);
	/* mensagens de opções */
	do {
	  puts ("    >>> 1 - Descartar variavel da memória");
	  puts ("    >>> 2 - Descartar variavel do arquivo");
	  puts ("    >>> 3 - Alterar nome");
	  printf ("    Digite a opção: ");
	  scanf (" %d", &op);
	  if (op<1 || op>3) {
	    puts ("\n>>> ERROR: Opção inválida");
	    puts (">>> Favor escolher uma opção válida\n");
	  }
	} while (op<1 || op>3);
	/* ações de acordo com as opções */
	switch (op) {
	  /* descartar variavel da memória */
	case 1:
	  /* seta a variavel da memoria como removido */
	  var.valores[i].qtdadeValores = REMOVIDO;
	  break;
	  /* descartar variavel do arquivo */
	case 2:
	  /* seta a variavel do arquivo como removido */
	  var.valores[var.qtdadeVariaveis].qtdadeValores = REMOVIDO;
	  break;
	  /* alterar nome */
	case 3:
	  /* recebe o novo nome */
	  printf ("    Novo nome: ");
	  scanf (" %s", nome);
	  /* copia o novo nome */
	  strcpy (var.nome[var.qtdadeVariaveis], nome);
	  break;
	default:
	  break;
	} /*switch*/
      } /*if*/
    } /*for*/
    /* copia a quantidade de valores */
    fscanf (inFile, " %d", &qtdadeValores);
    /* se a variavel já foi setada como removida, não deve ser inserida */
    if (var.valores[var.qtdadeVariaveis].qtdadeValores != REMOVIDO)
      var.valores[var.qtdadeVariaveis].qtdadeValores = qtdadeValores;
    /* percorre pelos valores */
    for (i=0; i<qtdadeValores; i++) {
      /* copia os valores */
      fscanf (inFile, " %f", &valores[i]);
      fgetc(inFile);
      var.valores[var.qtdadeVariaveis].valores[i] = valores[i];
    }
    /* se não for final de arquivo, retorna uma posição do seek */
    if (fgetc(inFile) != EOF)
      fseek(inFile, -1, SEEK_CUR);
  } /*while*/
  /* fecha o arquivo */
  fclose (inFile);
  /* apresenta mensagem de sucesso */
  puts ("\n>>> Leitura realizada com sucesso");
  return var;
}

/*******************************************************************/

int main (int argc, char *argv[]) {
  Variavel var;
  int op;

  var = inicializaVariavel();

  imprimeMenu ();

  do {
    printf ("\nDigite a opção: ");
    scanf (" %d", &op);
    switch (op) {
    case 1:
      var = inserir (var);
      break;
    case 2:
      gravar (var);
      break;
    case 3:
      var = ler (var);
      break;
    case 4:
      break;
    case 5:
      break;
    case 6:
      break;
    case 7:
      puts ("\n>>> Saída com exíto\n");
      exit(0);
      break;
    default:
      puts ("\n>>> ERROR: Opção inválida");
      puts (">>> Favor escolha outra opção\n");
    }
  } while (op != 7);
  
  
  

  return 0;
}
